package com.lczyfz.istep.modules.mobile.utils;

import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.Session;
import com.lczyfz.istep.common.config.Global;
import com.lczyfz.istep.common.utils.IdGen;
import com.lczyfz.istep.common.utils.StringUtils;
import com.lczyfz.istep.modules.mobile.entity.MobileFile;
import net.sf.json.JSONObject;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by jw on 2016/11/18.
 */
public class MobileUploadUtils implements Serializable {
    private static final long serialVersionUID = 1L;
    public static final long UNITSIZE = 314572800;
    //字符编码默认是utf-8
    private static String DEFAULTCHART = "UTF-8";
    private Connection conn;
    // 最大文件大小
    private long maxSize = UNITSIZE;
    // 定义允许上传的文件扩展名
    private Map<String, String> extMap = new HashMap<String, String>();
    // 文件的目录名
//    private String dirName = "mobile";
    private String dirName = "";
    //临时文件目录名
    private String tmpName = "tmp";
    //前端标签名称，默认是f
    private String divName = "file";
    //文件上传结果信息
    private String message;
    //是否成功
    private boolean success;
    //文件本地保存路径,单文件
    private String filePath;
    //文件名称,单文件
    private String fileSrcName ;
    //文件本地保存路径,多文件
    private String[] filePaths ;
    //文件名称,多文件
    private String[] fileSrcNames;

    private Logger logger = LoggerFactory.getLogger(getClass());
    public static final Map<String, List<Integer>> fileCountCache = new HashMap<>();
    //TODO:服务器路径
//    private static final String TEMP_DIR = "/home/tomcat-istep-8787/webapps/istep//userfiles/mobile/";
    private static final String TEMP_DIR = "/home/tomcat-istep-8787/webapps/istep//videoPlay/";
    //    private static final String RECORDTEMP_DIR = "/home/tomcat-istep-8787/webapps/istep//recordFiles/";
    //本地路径
//    private String TEMP_DIR = Global.getUserfilesBaseDir().replace("/", "") + "userfiles\\" + "mobile" + "\\";
//    private String TEMP_DIR = Global.getUserfilesBaseDir().replace("/", "") + "videoPlay\\";
    private String RECORDTEMP_DIR = Global.getUserfilesBaseDir().replace("/", "") + "recordFiles\\";


    public void setMaxSize(long maxSize) {
        this.maxSize = maxSize;
    }

    public MobileUploadUtils() {
        // 其中images,flashs,medias,files,对应文件夹名称,对应dirName
        // key文件夹名称
        // value该文件夹内可以上传文件的后缀名
        extMap.put("images", "gif,jpg,jpeg,png,bmp");
        extMap.put("flashs", "swf,flv");
        extMap.put("medias", "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb,mp4");
        extMap.put("files", "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2,gif,jpg,jpeg,png,bmp,apk,ipa");

    }
    public MobileUploadUtils(String divName) {
        this.divName = divName;
        // 其中images,flashs,medias,files,对应文件夹名称,对应dirName
        // key文件夹名称
        // value该文件夹内可以上传文件的后缀名
        extMap.put("images", "gif,jpg,jpeg,png,bmp");
        extMap.put("flashs", "swf,flv");
        extMap.put("medias", "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb");
        extMap.put("files", "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2,gif,jpg,jpeg,png,bmp,apk,ipa");

    }
    @Override
    public String toString() {
        return ReflectionToStringBuilder.toString(this);
    }
    /**
     * 单文件上传
     *
     * @param request
     * @return 操作结果
     */
    public MobileFile uploadFile(HttpServletRequest request) {
        Map resultMap = new HashMap();
        //转型为MultipartHttpRequest
        MultipartHttpServletRequest multipartRequest  =  (MultipartHttpServletRequest) request;
        //获得文件,f为前端标签name。
        MultipartFile file  =  multipartRequest.getFile(this.divName);
        if(file==null||file.isEmpty())
        	return null;
        return saveFile(file);
    }


    /**
     * 单文件上传
     *
     * @param file
     * @return 操作结果
     */
    public MobileFile uploadFile(MultipartFile file) {
        if(file.isEmpty())
            return null;
        return saveFile(file);
    }

    /**
     * 多文件上传
     *
     * @param request,
     * @return 操作结果
     */
    public List<MobileFile> uploadFiles(HttpServletRequest request) {
        Map resultMap = new HashMap();
//        MultipartResolver resolver = new CommonsMultipartResolver(request.getSession().getServletContext());
        //转型为MultipartHttpRequest
        if (request.getClass() == ShiroHttpServletRequest.class){
            List<MobileFile> list = new ArrayList<>();
            return list;
        }
        MultipartHttpServletRequest multipartRequest  =  (MultipartHttpServletRequest) request;
        System.out.println("-------------"+multipartRequest.getMultiFileMap());
        //获得文件,f为前端标签name。
        List<MultipartFile> fileList = new ArrayList<MultipartFile>();
        List<MobileFile> lgSysFileList = new ArrayList<MobileFile>();
        fileList = multipartRequest.getFiles(this.divName);
        this.filePaths = new String[fileList.size()];
        this.fileSrcNames = new String[fileList.size()];
        for (int i=0 ; i < fileList.size() ; i++){
            MobileFile sysFile = new MobileFile();
            sysFile = saveFile(fileList.get(i));
            System.out.print("上传工具类里面的sysFile"+sysFile);

            if (sysFile == null){
                this.message = "上传第" + i + "个文件出错," + this.message;
                return lgSysFileList;
            }else {
                lgSysFileList.add(sysFile);
                this.success = true;
                this.filePaths[i] = this.filePath;
                this.fileSrcNames[i] = this.fileSrcName;
                this.filePath = "";
                this.fileSrcName = "";
            }
        }
        this.message = "上传"+fileList.size()+"个文件成功";
        return lgSysFileList;
    }
    /** **********************私有方法********************************* */
    /**
     * 文件验证
     *
     * @param file
     * @return 验证结果
     */
    private boolean validateFile(MultipartFile file) {
        if(file == null || file.getSize() == 0 ){
            this.message = "上传文件不存在";
            return false;
        }

        if (this.maxSize == -1 ){
            //-1表示不限制大小
        }else if (file.getSize() > this.maxSize || file.getSize() < 0){
            this.message = "上传文件过大";
            return false;
        }
        //文件名称中包含多个"."
        String fileName = file.getOriginalFilename();
        if (fileName.split(".").length > 2){
            this.message = "文件格式不正确";
            return false;
        }

        String suffix = fileName.substring(fileName.lastIndexOf(".")+1,fileName.length());
        if(!this.extMap.get("medias").toString().contains(suffix)){
            this.message = "文件格式不正确";
            return false;
        }
        return true;
    }
    /**
     * 单文件上传
     *
     * @param file
     * @return 是否操作成功
     */
    private MobileFile saveFile(MultipartFile file) {
        System.out.print("调用了一次");

        MobileFile lgSysFile = new MobileFile();
        //文件验证
        if (!validateFile(file)){
            this.success = false;
            return lgSysFile;
        }
        System.out.println("文件验证通过===");

        //得到上传的文件名称
        String fileName = file.getOriginalFilename();
        //得到后缀
        String suffix = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
        //为了保存名称的唯一性，使用uuid
        String name = IdGen.uuid();
        //客户端访问路径
        String filePath = Global.USERFILES_BASE_URL+this.dirName + "/" + name + "."+suffix;
        System.out.println("----filePath----"+filePath);
        System.out.println("----fileName----"+fileName);

        //本地保存路径
//        String fileLocalPath = Global.getUserfilesBaseDir().replace("/","")+ "userfiles\\" + this.dirName + "\\" + name + "."+suffix;
        //本地保存路径
        String fileLocalPath = Global.getUserfilesBaseDir() + Global.USERFILES_BASE_URL + this.dirName + "/" + name + "."+suffix;

        System.out.println("----fileLocalPath----" + fileLocalPath);
        //创建目录
        File saveDirFile = new File(fileLocalPath);
        if (!saveDirFile.exists()) {
            saveDirFile.mkdirs();
        }
        try {
//            LgSysFileService lgSysFileService = ApplicationContext.get(LgSysFileService.class);
            //MultipartFile类型转为file
            file.transferTo(saveDirFile);

            lgSysFile.setUrl(filePath);
            lgSysFile.setName(fileName);
            lgSysFile.setFormat(suffix);
            lgSysFile.setUrlLocal(fileLocalPath);
            this.message = "上传成功!";
            this.success = true;
            this.filePath = filePath;
            this.fileSrcName = fileName;
            return lgSysFile;
        } catch (Exception e) {
            e.printStackTrace();
            this.message = e.getMessage();
            this.success = false;
            return lgSysFile;
        }
    }



    /**
     * @param request
     * @return
     * @throws IOException
     */

    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> batchUploadFile(MultipartHttpServletRequest request) throws IOException {
        String path = request.getSession().getServletContext().getRealPath("");
        System.out.println("服务器路径：" + path);

        System.out.println("temp_dir==" + TEMP_DIR);
        Map<String, Object> dataMap = new HashMap<>();
        mkTmpDir();

        //获取上传的参数
        String index = request.getParameter("index");
        int fileCount =
                Integer.valueOf(request.getParameter("fileCount"));
        MultipartFile multipartFile = request.getFile("file");
        //TODO:
        //得到上传的文件名称
        String fileName = multipartFile.getOriginalFilename();


        //得到后缀
        String suffix = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
        //为了保存名称的唯一性，使用uuid
//        String name = IdGen.uuid();
        String originalFilename = request.getParameter("insurance");

        //客户端访问路径
        String filePath = Global.USERFILES_BASE_URL + this.dirName + "/" + originalFilename + "." + suffix;
        System.out.println("----filePath----" + filePath);
        System.out.println("----fileName----" + fileName);

        //本地保存路径
//        String fileLocalPath = Global.getUserfilesBaseDir().replace("/","")+ "userfiles\\" + this.dirName + "\\" + originalFilename + "."+suffix;
        //本地保存路径
        String fileLocalPath = Global.getUserfilesBaseDir() + Global.USERFILES_BASE_URL + this.dirName + "/" + originalFilename + "." + suffix;
        System.out.println("----fileLocalPath----" + fileLocalPath);

        dataMap.put("fileName", fileName);
        dataMap.put("suffix", suffix);
        dataMap.put("url", filePath);
        dataMap.put("fileLocalPath", fileLocalPath);


        //获取文件并创建文件分片
//        String originalFilename = multipartFile.getOriginalFilename();

        //TODO:临时文件名字？
        File fileChunk = new File(TEMP_DIR
                + originalFilename
                + ".temp"
                + index);

        //查看该文件是否上传过
        List<Integer> uploadedList =
                fileCountCache.get(originalFilename);
        if (uploadedList == null) {
            uploadedList = new ArrayList<>(fileCount);
            fileCountCache.put(originalFilename, uploadedList);
        }

        Integer currentCount = uploadedList.size();

        dataMap.put("data", uploadedList);

        if (fileChunk.exists()) {
            return dataMap;
        }

        //将上传的文件片段保存到tmp目录下
        FileOutputStream fos = new FileOutputStream(fileChunk);
        InputStream in = multipartFile.getInputStream();
        IOUtils.copy(in, fos);
        fos.close();
        in.close();

        uploadedList.add(Integer.valueOf(index));
        currentCount = uploadedList.size();

        //判断文件是否所有片段都上传完毕
        if (currentCount == fileCount) {
            File targetFile = new File(TEMP_DIR + originalFilename + "." + suffix);
            if (targetFile.exists()) {
                targetFile.delete();
            }
            //将文件片合成一个文件
            FileOutputStream targetOut =
                    new FileOutputStream(targetFile, true);
            for (int i = 0; i < fileCount; i++) {
                File tempFile =
                        new File(TEMP_DIR
                                + originalFilename
                                + ".temp"
                                + i);
                FileInputStream tempIs = new FileInputStream(tempFile);
                IOUtils.copy(tempIs, targetOut);
                tempIs.close();
                if (tempFile.exists()) {
                    tempFile.delete();
                }
            }
            targetOut.close();
            System.out.println("文件拼接完成！");
            //清空该文件对应的已上传片段号缓存
            fileCountCache.put(originalFilename, null);
        }
        dataMap.put("data", uploadedList);
        return dataMap;
    }

    public List<Integer> getChunk(String filename) {
        for (Map.Entry<String, List<Integer>> entry : fileCountCache.entrySet()) {
            System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
        }
        return fileCountCache.get(filename);
    }

    //创建存放上传的文件目录
    public boolean mkTmpDir() {
        File file = new File(TEMP_DIR);
        if (!file.exists()) {
            return file.mkdirs();
        }
        return false;
    }


    /** ************************录音文件***************************** */
    /**
     * @param request
     * @return
     */
    public MobileFile recordUploadFile(HttpServletRequest request, String uniId) {
        Map resultMap = new HashMap();
        //转型为MultipartHttpRequest
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        //获得文件,f为前端标签name。
        MultipartFile file = multipartRequest.getFile(this.divName);
        if (file == null || file.isEmpty())
            return null;
        return recordSaveFile(file, uniId);
    }

    /**
     * 录音单文件上传
     *
     * @param file
     * @return 是否操作成功
     */
    private MobileFile recordSaveFile(MultipartFile file, String uniId) {
        System.out.print("调用了一次");

        MobileFile lgSysFile = new MobileFile();
        //文件验证
        if (!validateFile(file)) {
            this.success = false;
            return lgSysFile;
        }
        System.out.println("文件验证通过===");

        //得到上传的文件名称
        String fileName = file.getOriginalFilename();
        //得到后缀
        String suffix = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
        //为了保存名称的唯一性，使用uuid
//        String name = IdGen.uuid();
        String name = uniId;
        //客户端访问路径
        String filePath = Global.RECORDFILES_BASE_URL + this.dirName + "/" + name + "." + suffix;
        System.out.println("----filePath----" + filePath);
        System.out.println("----fileName----" + fileName);

        //本地保存路径
//        String fileLocalPath = Global.getUserfilesBaseDir().replace("/","")+ "userfiles\\" + this.dirName + "\\" + name + "."+suffix;
        //本地保存路径
        String fileLocalPath = Global.getUserfilesBaseDir() + Global.RECORDFILES_BASE_URL + this.dirName + "/" + name + "." + suffix;

        System.out.println("----fileLocalPath----" + fileLocalPath);
        //创建目录
        File saveDirFile = new File(fileLocalPath);
        if (!saveDirFile.exists()) {
            saveDirFile.mkdirs();
        }
        try {
            //MultipartFile类型转为file
            file.transferTo(saveDirFile);

            File recordFile = new File(fileLocalPath);
            System.out.println("recordFile=" + recordFile);
            lgSysFile.setUrl(filePath);
            lgSysFile.setName(fileName);
            lgSysFile.setFormat(suffix);
            lgSysFile.setUrlLocal(fileLocalPath);
            //TODO:执行python脚本
            System.out.println("start python");
            //需传入的参数
            String a = "aaa", b = "bbb", c = "ccc", d = "ddd";
            //设置命令行传入参数
            String[] args = new String[]{"python", "C:\\Users\\hpp\\Desktop\\test1.py", a, b, c, d};
            Process pr = Runtime.getRuntime().exec(args);
            //TODO:该方法只能传递字符串
//            Process pr = Runtime.getRuntime().exec("python C:\\Users\\hpp\\Desktop\\test1.py C:\\Users\\hpp\\Desktop\\test1.mp4");

            BufferedReader in = new BufferedReader(new InputStreamReader(pr.getInputStream()));
            String line;

            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
            in.close();
            pr.waitFor();
            System.out.println("end");

            this.message = "上传成功!";
            this.success = true;
            this.filePath = filePath;
            this.fileSrcName = fileName;
            return lgSysFile;
        } catch (Exception e) {
            e.printStackTrace();
            this.message = e.getMessage();
            this.success = false;
            return lgSysFile;
        }
    }

    /**
     * 上传录音文件
     *
     * @param request
     * @return
     */
    public Map<String, Object> recordSaveFile(HttpServletRequest request) {
        Map<String, Object> result = new HashMap<>();
        try {
            MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
            //获得文件,f为前端标签name。
            MultipartFile file = multipartRequest.getFile("file");
            if (!validateFile(file)) {
                result.put("success", false);
                result.put("msg", this.message);
                return result;
            }
            System.out.println("文件验证通过===");
            InputStream in = file.getInputStream(); // 这里是你已经存在的输入流
            FileInputStream fin = null; // 转换后的文件输入流
            // 如果是FileInputStream类型，进行转换
            if (in instanceof FileInputStream) {
                fin = (FileInputStream) in;
//                FileInputStream in=new FileInputStream(new File("F:\\istep\\istep\\src\\main\\webapp\\recordFiles\\333.mp3"));
//                boolean flag = FileManagerByFtp.uploadFile("139.196.48.196", 21, "root", "Lczy2016cfq", "/home/tomcat-istep-8787/webapps/istep/videoPlay/", "444.mp3", fin);
//                boolean flag = FileManagerByFtp.uploadFile("218.193.113.149", 21, "ubuntu", "123", "/home/ubuntu/Desktop/music_rec/user_sim/audio", "444.mp3", fin);
//                if(flag){
                if (true) {
//
                    logger.debug("文件上传成功！");
//                    RemoteExecuteCommand rec=new RemoteExecuteCommand("218.193.113.149", "ubuntu","123");
                    //执行命令
                    try {
                        if (login("218.193.113.149", "ubuntu", "123")) {

                            logger.debug("=====第一个步骤=====");
                            Session session = conn.openSession();//打开一个会话
                            //TODO:多条命令
                            session.execCommand("cd /home/ubuntu/Desktop/music_rec/user_sim;echo \"123\" | sudo  -S ./caculate_tim_sim.sh similar");//执行命令
                            String result1 = RemoteExecuteCommand.processStdout(session.getStdout(), DEFAULTCHART);
                            //如果为得到标准输出为空，说明脚本执行出错了
                            if (StringUtils.isBlank(result1)) {
                                System.out.println("脚本出错");
                                result1 = RemoteExecuteCommand.processStdout(session.getStderr(), DEFAULTCHART);
                            }
//                            logger.debug(result1);
                            session.close();

                            logger.debug("=====第二个步骤=====");
                            Session session2 = conn.openSession();//打开一个会话
                            //TODO:多条命令
                            session2.execCommand("cd /home/ubuntu/Desktop/music_rec/user_sim/result;cat xyy_result_m10d.json");//执行命令
                            String result2 = RemoteExecuteCommand.processStdout(session2.getStdout(), DEFAULTCHART);
                            //如果为得到标准输出为空，说明脚本执行出错了
                            if (StringUtils.isBlank(result2)) {
                                System.out.println("脚本出错");
                                result2 = RemoteExecuteCommand.processStdout(session2.getStderr(), DEFAULTCHART);
                            }
                            result.put("jsonData", JSONObject.fromObject(result2));
                            logger.debug(JSONObject.fromObject(result2).toString());
                            session2.close();

                            logger.debug("=====第三个步骤=====");
                            Session session3 = conn.openSession();//打开一个会话
                            //TODO:多条命令
                            session3.execCommand("cd /home/ubuntu/Desktop/music_rec/effective_range_of_singing_voice;python batch.py");//执行命令
                            String result3 = RemoteExecuteCommand.processStdout(session3.getStdout(), DEFAULTCHART);
                            //如果为得到标准输出为空，说明脚本执行出错了
                            if (StringUtils.isBlank(result3)) {
                                System.out.println("脚本出错");
                                result3 = RemoteExecuteCommand.processStdout(session3.getStderr(), DEFAULTCHART);
                            }
//                            logger.debug(result3);
                            session3.close();

                            logger.debug("=====第四个步骤=====");
                            Session session4 = conn.openSession();//打开一个会话
                            //TODO:多条命令
                            session4.execCommand("cd /home/ubuntu/Desktop/music_rec/recommendation;python recomendation.py");//执行命令
                            String result4 = RemoteExecuteCommand.processStdoutExceptLineOne(session4.getStdout(), DEFAULTCHART);
                            //如果为得到标准输出为空，说明脚本执行出错了
                            if (StringUtils.isBlank(result4)) {
                                System.out.println("脚本出错");
                                result4 = RemoteExecuteCommand.processStdoutExceptLineOne(session4.getStderr(), DEFAULTCHART);
                            }
                            result4 = result4.replace("\t", "_").replace("\n", ",");
                            result.put("recResult", result4);
                            logger.debug(result4);
                            session4.close();

                            conn.close();
                            result.put("success", true);
                            result.put("msg", "上传成功！");
                        } else {
                            result.put("success", false);
                            result.put("msg", "服务器连接失败！");
                            logger.debug("服务器连接失败!");
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                } else {
                    result.put("success", false);
                    result.put("msg", "文件上传失败！");
                }
//                System.out.println(flag);
            } else { // 否则，转型失败
                throw new Exception("文件转型失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 连接Linux服务器
     *
     * @param ip
     * @param userName
     * @param userPwd
     * @return
     */
    public Boolean login(String ip, String userName, String userPwd) {
        boolean flg = false;
        try {
            conn = new Connection(ip);
            conn.connect();//连接
            flg = conn.authenticateWithPassword(userName, userPwd);//认证
            if (flg) {
                System.out.println("认证成功！");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return flg;
    }

    /**
     * 连接执行指令
     */


    /** **********************get/set方法********************************* */
    public Map<String, String> getExtMap() {
        return extMap;
    }

    public void setExtMap(Map<String, String> extMap) {
        this.extMap = extMap;
    }

    public String getDirName() {
        return dirName;
    }

    public void setDirName(String dirName) {
        this.dirName = dirName;
    }
    public long getMaxSize() {
        return maxSize;
    }

    public String getMessage() {
        return message;
    }

    public String getFilePath() {
        return filePath;
    }

    public String getDivName() {
        return divName;
    }

    public void setDivName(String divName) {
        this.divName = divName;
    }

    public String[] getFilePaths() {
        return filePaths;
    }

    public String getFileSrcName() {
        return fileSrcName;
    }

    public String[] getFileSrcNames() {
        return fileSrcNames;
    }

    public boolean isSuccess() {
        return success;
    }

    public String getTmpName() {
        return tmpName;
    }

    public void setTmpName(String tmpName) {
        this.tmpName = tmpName;
    }
}
